package app;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import platform.database.Condition;
import platform.database.Order;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DBController {
    private Log logger = LogFactory.getLog(DBController.class);
    private static DBController instance;
    AppRemoteConnector connector;

    public static DBController getInstance() {
        if (instance == null) {
            synchronized (DBController.class) {
                if (instance == null) {
                    instance = new DBController();
                }
            }
        }
        return instance;
    }

    private DBController() {
        connector = AppRemoteConnector.getInstance();
    }

    public boolean createTable(String tableName, String primaryKey, List<String> header, int rowLimit) {
        JSONObject jo = new JSONObject(5);
        jo.put("api", "db_create");
        jo.put("app_name", connector.getAppName());
        jo.put("table_name", tableName);
        jo.put("primary_key", primaryKey);
        jo.put("row_limit", rowLimit);
        JSONArray headerJson = new JSONArray();
        headerJson.addAll(header);
        jo.put("header", headerJson);
        connector.getTCP().send(jo.toJSONString());

        boolean state = false;
        String recv = connector.getTCP().recv();
        if (recv != null) {
            state = JSON.parseObject(recv).getBooleanValue("state");
        }
        logger.info(String.format("[%s]: createTable(%s, %s, %s) -> %s", connector.getAppName(), tableName, primaryKey, header, state));
        return state;
    }

    public boolean deleteTable(String tableName) {
        JSONObject jo = new JSONObject(3);
        jo.put("api", "db_drop");
        jo.put("app_name", connector.getAppName());
        jo.put("table_name", tableName);
        connector.getTCP().send(jo.toJSONString());

        boolean state = false;
        String recv = connector.getTCP().recv();
        if (recv != null) {
            state = JSON.parseObject(recv).getBooleanValue("state");
        }
        logger.info(String.format("[%s]: deleteTable(%s) -> %s", connector.getAppName(), tableName, state));
        return state;
    }

    public boolean insertRow(String tableName, Map<String, Object> row) {
        JSONObject jo = new JSONObject(4);
        jo.put("api", "db_insert");
        jo.put("app_name", connector.getAppName());
        jo.put("table_name", tableName);
        JSONObject rowJson = new JSONObject();
        rowJson.putAll(row);
        jo.put("row", rowJson);
        connector.getTCP().send(jo.toJSONString());

        boolean state = false;
        String recv = connector.getTCP().recv();
        if (recv != null) {
            state = JSON.parseObject(recv).getBooleanValue("state");
        }
        logger.info(String.format("[%s]: insertRow(%s, %s) -> %s", connector.getAppName(), tableName, row, state));
        return state;
    }

//    public boolean insertRowList(String tableName, List<Map<String, Object>> rows) {
//        JSONObject jo = new JSONObject(4);
//        jo.put("api", "db_inserts");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        JSONArray rowsJson = new JSONArray();
//        rowsJson.addAll(rows);
//        jo.put("rows", rowsJson);
//        connector.getTCP().send(jo.toJSONString());
//
//        boolean state = false;
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            state = JSON.parseObject(recv).getBooleanValue("state");
//        }
//        logger.info(String.format("[%s]: insertRowList(%s, %s) -> %s", connector.getAppName(), tableName, rows, state));
//        return state;
//    }

//    public boolean updateRow(String tableName, Map<String, Object> row) {
//        JSONObject jo = new JSONObject(4);
//        jo.put("api", "db_update");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        JSONObject rowJson = new JSONObject();
//        rowJson.putAll(row);
//        jo.put("row", rowJson);
//        connector.getTCP().send(jo.toJSONString());
//
//        boolean state = false;
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            state = JSON.parseObject(recv).getBooleanValue("state");
//        }
//        logger.info(String.format("[%s]: updateRow(%s, %s) -> %s", connector.getAppName(), tableName, row, state));
//        return state;
//    }

//    public boolean deleteRow(String tableName, int row) {
//        JSONObject jo = new JSONObject(6);
//        jo.put("api", "db_delete");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("row", row);
//        connector.getTCP().send(jo.toJSONString());
//
//        boolean state = false;
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            state = JSON.parseObject(recv).getBooleanValue("state");
//        }
//        logger.info(String.format("[%s]: deleteRow(%s, %d) -> %s", connector.getAppName(), tableName, row, state));
//        return state;
//    }
//
//    public boolean deleteRowList(String tableName, int rows) {
//        JSONObject jo = new JSONObject(7);
//        jo.put("api", "db_deletes");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("rows", rows);
//        connector.getTCP().send(jo.toJSONString());
//
//        boolean state = false;
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            state = JSON.parseObject(recv).getBooleanValue("state");
//        }
//        logger.info(String.format("[%s]: deleteRowList(%s, %d) -> %s", connector.getAppName(), tableName,
//                rows, state));
//        return state;
//    }

//    public Map<String, Object> getRow(String tableName, int row, List<String> columns,
//                                      List<Condition> conditions, List<Order> orders) {
//        JSONObject jo = new JSONObject(6);
//        jo.put("api", "db_row");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("row", row);
//        if (columns != null) {
//            JSONArray columnsJson = new JSONArray();
//            columnsJson.addAll(columns);
//            jo.put("columns", columnsJson);
//        }
//        if (conditions != null) {
//            JSONArray conditionsJson = new JSONArray();
//            conditions.forEach(condition -> conditionsJson.add(condition.toJSONObject()));
//            jo.put("conditions", conditionsJson);
//        }
//        if (orders != null) {
//            JSONArray orderBysJson = new JSONArray();
//            orders.forEach(order -> orderBysJson.add(order.toJSONObject()));
//            jo.put("orders", orderBysJson);
//        }
//        connector.getTCP().send(jo.toJSONString());
//
//        Map<String, Object> ret = new HashMap<>();
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            ret.putAll(JSON.parseObject(recv));
//        }
//        logger.info(String.format("[%s]: getRow(%s, %d, %s, %s, %s) -> %s", connector.getAppName(), tableName, row, columns, conditions, orders, ret));
//        return ret;
//    }

//    public List<Map<String, Object>> getRowList(String tableName, int rows, List<String> columns,
//                                                       List<Condition> conditions, List<Order> orders) {
//        JSONObject jo = new JSONObject(7);
//        jo.put("api", "db_rows");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("rows", rows);
//        if (columns != null) {
//            JSONArray columnsJson = new JSONArray();
//            columnsJson.addAll(columns);
//            jo.put("columns", columnsJson);
//        }
//        if (conditions != null) {
//            JSONArray conditionsJson = new JSONArray();
//            conditions.forEach(condition -> conditionsJson.add(condition.toJSONObject()));
//            jo.put("conditions", conditionsJson);
//        }
//        if (orders != null) {
//            JSONArray orderBysJson = new JSONArray();
//            orders.forEach(order -> orderBysJson.add(order.toJSONObject()));
//            jo.put("orders", orderBysJson);
//        }
//        connector.getTCP().send(jo.toJSONString());
//
//        List<Map<String, Object>> ret = new ArrayList<>();
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            JSON.parseArray(recv).forEach(obj -> {
//                Map<String, Object> row = new HashMap<>((JSONObject) obj);
//                ret.add(row);
//            });
//        }
//        logger.info(String.format("[%s]: getRowList(%s, %d, %s, %s, %s) -> %s", connector.getAppName(), tableName, rows, columns, conditions, orders, ret));
//        return ret;
//    }

    public List<Map<String, Object>> getAllRows(String tableName) {
        JSONObject jo = new JSONObject(3);
        jo.put("api", "db_rows");
        jo.put("app_name", connector.getAppName());
        jo.put("table_name", tableName);
        jo.put("rows", -1);
        connector.getTCP().send(jo.toJSONString());

        List<Map<String, Object>> ret = new ArrayList<>();
        String recv = connector.getTCP().recv();
        if (recv != null) {
            JSON.parseArray(recv).forEach(obj -> {
                Map<String, Object> row = new HashMap<>((JSONObject) obj);
                ret.add(row);
            });
        }
        logger.info(String.format("[%s]: getAllRows(%s) -> %s", connector.getAppName(), tableName, ret));
        return ret;
    }

//    public List<Object> getColumn(String tableName, int rows, String column) {
//        JSONObject jo = new JSONObject(6);
//        jo.put("api", "db_column");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("rows", rows);
//        jo.put("column", column);
//        connector.getTCP().send(jo.toJSONString());
//
//        List<Object> ret = new ArrayList<>();
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            JSON.parseArray(recv).forEach(obj -> {
//                Object value;
//                try {
//                    value = Integer.valueOf(obj.toString());
//                } catch (Exception e) {
//                    try {
//                        value = Double.valueOf(obj.toString());
//                    } catch (Exception e1) {
//                        if (obj.toString().equalsIgnoreCase("true")) {
//                            value = true;
//                        } else if (obj.toString().equalsIgnoreCase("false")) {
//                            value = false;
//                        } else {
//                            value = obj.toString();
//                        }
//                    }
//                }
//                ret.add(value);
//            });
//        }
//        logger.info(String.format("[%s]: getColumn(%s, %d, %s) -> %s", connector.getAppName(), tableName, rows, column, ret));
//        return ret;
//    }
//
//    public Map<String, List<Object>> getColumnMap(String tableName, int rows, List<String> columns) {
//        JSONObject jo = new JSONObject(6);
//        jo.put("api", "db_columns");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("rows", rows);
//        if (columns != null) {
//            JSONArray columnsJson = new JSONArray();
//            columnsJson.addAll(columns);
//            jo.put("columns", columnsJson);
//        }
//        connector.getTCP().send(jo.toJSONString());
//
//        Map<String, List<Object>> ret = new HashMap<>();
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            JSONObject recvJson = JSON.parseObject(recv);
//            for (String column : recvJson.keySet()) {
//                List<Object> values = new ArrayList<>();
//                JSONArray valuesJson = recvJson.getJSONArray(column);
//                for (Object valueJson : valuesJson) {
//                    Object value;
//                    try {
//                        value = Integer.valueOf(valueJson.toString());
//                    } catch (Exception e) {
//                        try {
//                            value = Double.valueOf(valueJson.toString());
//                        } catch (Exception e1) {
//                            if (valueJson.toString().equalsIgnoreCase("true")) {
//                                value = true;
//                            } else if (valueJson.toString().equalsIgnoreCase("false")) {
//                                value = false;
//                            } else {
//                                value = valueJson.toString();
//                            }
//                        }
//                    }
//                    values.add(value);
//                }
//                ret.put(column, values);
//            }
//        }
//        logger.info(String.format("[%s]: getColumnMap(%s, %d, %s) -> %s", connector.getAppName(), tableName, rows, columns, ret));
//        return ret;
//    }
//
//    public Object getCell(String tableName, int row, String column) {
//        JSONObject jo = new JSONObject(6);
//        jo.put("api", "db_cell");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        jo.put("row", row);
//        jo.put("column", column);
//        connector.getTCP().send(jo.toJSONString());
//
//        Object ret = null;
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            try {
//                ret = Integer.valueOf(recv);
//            } catch (Exception e) {
//                try {
//                    ret = Double.valueOf(recv);
//                } catch (Exception e1) {
//                    if (recv.equalsIgnoreCase("true")) {
//                        ret = true;
//                    } else if (recv.equalsIgnoreCase("false")) {
//                        ret = false;
//                    } else {
//                        ret = recv;
//                    }
//                }
//            }
//        }
//        logger.info(String.format("[%s]: getCell(%s, %d, %s, %s, %s) -> %s", connector.getAppName(), tableName, row, column, ret));
//        return ret;
//    }
//
//    public List<String> getHeader(String tableName) {
//        JSONObject jo = new JSONObject(3);
//        jo.put("api", "db_header");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        connector.getTCP().send(jo.toJSONString());
//
//        List<String> ret = new ArrayList<>();
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            ret.addAll(JSON.parseArray(recv, String.class));
//        }
//        logger.info(String.format("[%s]: getHeader(%s) -> %s", connector.getAppName(), tableName, ret));
//        return ret;
//    }
//
//    public int getCount(String tableName) {
//        JSONObject jo = new JSONObject(3);
//        jo.put("api", "db_count");
//        jo.put("app_name", connector.getAppName());
//        jo.put("table_name", tableName);
//        connector.getTCP().send(jo.toJSONString());
//
//        int ret = 0;
//        String recv = connector.getTCP().recv();
//        if (recv != null) {
//            ret = JSON.parseObject(recv).getIntValue("size");
//        }
//        logger.info(String.format("[%s]: getCount(%s) -> %s", connector.getAppName(), tableName, ret));
//        return ret;
//    }

    //public boolean createTable(String tableName, String primaryKey, List<String> header);
    //public boolean deleteTable(String tableName);
    //public boolean insertRow(String tableName, Map<String, Object> row);
    //public boolean updateRow(String tableName, Map<String, Object> row);
    //public boolean deleteRow(String tableName, int row, List<Condition> conditions, List<Order> orders);
    //public boolean deleteRowList(String tableName, int rows, List<Condition> conditions, List<Order> orders);
    //public Map<String, Object> getRow(String tableName, int row, List<String> columns, List<Condition> conditions, List<Order> orders);
    //public List<Map<String, Object>> getRowList(String tableName, int rows, List<String> columns, List<Condition> conditions, List<Order> orders);
    //public List<Object> getColumn(String tableName, int rows, String column, List<Condition> conditions, List<Order> orders);
    //public Map<String, List<Object>> getColumnMap(String tableName, int rows, List<String> columns, List<Condition> conditions, List<Order> orders);
    //public Object getCell(String tableName, int row, String column, List<Condition> conditions, List<Order> orders);
    //public List<String> getHeader(String tableName);
    //public int getCount(String tableName);
}
